require 'pp'
# doctest_require: 'enhanced_arg_parser'
#
# another nicety of this is that it can easily roll over into existing code, gradually [existing code syntax will work with it]


# ltodo: the class checker === :) [and could be optimized, even]

def has_one_in_middle *as
  p1, p2, p3, p4 = as.args [:p1], {:p2 => 4}, {:p3 => 46}, {:p4 =>  45}
end

# doctest: it takes args like normal ruby functions
# >> get_some_normal_args 3, 4
# => [3, 4]
# >> get_some_normal_args 3, 4
# => [3, 4]
# >> get_some_normal_args 3, 4
# => [3, 4]

# doctest: it allows for optional args  
# >> has_one_in_middle 2, 3, :p4 => 7
# [2, 3, 46, 7]
 
# doctest: raises -- it catches if you name something twice on accident
# >> has_one_in_middle 2, 3, :p2 => 7
#RuntimeError "already named it"

# TOTEST if they pass too many args...what then?

# we require the requireds to always be in an array. Always. 
# but then what if you just have optionals?  Then they must NOT be in an array.  A first array is always for requireds.
def get_some_normal_args *args
    ver, docu2 = args.args [:ver, :docu2]
    [ver, docu2]
end

# dt: allows you to assign default values for variables
# ex: you don't pass in anything, it still works
# >> get_some_default_valued_args
# => [3, 4]
def get_some_default_valued_args *args
   ver, docu2 = args.args({:ver => 3}, {:docu2 => 4})
   [ver, docu2]
end


# doctest: (raises) requires variables, if they don't have a default value
#  >> get_some_normal_args 3
#RuntimeError: not enough parameters passed to function!
#	from ./works.rb:34:in `parse'
#	from ./works.rb:31:in `each'
#	from ./works.rb:31:in `parse'
#	from ./works.rb:6:in `get_some_normal_args'


def gets_named_mixed *args
  ver, docu2, docu3 = args.args({:ver => 3}, {:docu2 => 4})
  [ver, docu2]
end


# doctest: it lets you pass in named args
# >> gets_named_mixed :docu2 => 5
# => [3, 5]

# doctest: it lets you pass in named args
# >> gets_named_mixed :ver => 5
# => [5, 4]

# doctest: if you want them to always be required to be passed in, you can specify them in the method declaration
# or pass the constant :REQ to their default value

def has_some_that_must_be_there arg1, arg2, *args
  ver, docu = args.args [:ver], {:docu => 3}
end

def works_without_opening_reqs *args
   p1, p2, p3, p5 = args.args [:p1, :p2], {:p3 => 4}, {:p5 => 6}
end

# doctest:works without opening reqs
# >> works_without_opening_reqs 3, 4
# => [3, 4, 4, 6]

def raises_if_you_pass_extra *args
  a, b = args.args :ver, 3
end

# doctest: raises an exception if you pass parameters that aren't recognized
# >> raises_if_you_pass_extra :abc => 'def'
# doctest: raises an exception if you pass extra parameters
# >> raises_if_you_pass_extra 3, 4

def leaves_args_array_untouched *args
  a, b = args.args [:a, :b] # HMM TODO decide if just one should be optionals or normals....hmm...maybe people want to use it for normal functions, too--then it's ugly! ugly I tell you! ugly!
  args
end
# doctest: still has an args array if wanted to examine it later in the function -- leaves it untouched
# >> leaves_args_array_untouched 1, 2
# => [1, 2]

def errs_on_mis_type *args
  args.args [:a, :b], [:c] # should be {:c => 3}
end 

# doctest: raises if you dont pass it a hash for optionals
# >> errs_on_mis_type 3, 4
# #ErrorOfSomeType: # wow doctest really stinks with these currently

def works_with_single *args
  abc = args.args :abc => 3
end
# doctest: it works with single variables.
# >> works_with_single
# => 3
# >> works_with_single 4
# => 4 

# doctest: works with lots of optionals
def lots_of_optionals *as
  a, b, c, d, e = as.args( {:a => 1}, {:b => 2}, {:c => 3}, {:d => 4}, {:e => 5} )
end
# >> lots_of_optionals
# => [1, 2, 3, 4, 5]